require_relative "lib/xml_helper"
require_relative "lib/xml_model"

module XMLEditor
  class Menu

  public
    def initialize
      @builder
      @xml_document
      main_menu
      @current_file_name
    end

    def main_menu
      puts ""
      puts "/////// MAIN MENU /////////"
      puts "(1) Open file            //"
      puts "(2) New file             //"
      puts "(X) Exit application     //"
      puts "///////////////////////////"
      puts ""

      print "~ Please choose a submenu with number: "
      selected = gets.chomp

      case selected.downcase
      when "1"
        open_file_dialog
      when "2"
        new_file_dialog
      when "x"
        exit_application_dialog
      else
        puts "! Not a valid submenu. Try again!"
        main_menu
      end
    end

    def file_menu
      puts ""
      puts "// #{@current_file_name}"
      puts "//"
      puts "/////// FILE MENU /////////"
      puts "(1) Edit XML declaration //"
      puts "(2) Edit XML body        //"
      puts "(3) Save file            //"
      puts "(X) Close file           //"
      puts "///////////////////////////"
      puts ""

      print "~ Please choose a submenu with number: "
      selected = gets.chomp

      case selected.downcase
      when "1"
        edit_declaration_dialog
      when "2"
        edit_xml_menu
      when "3"
        save_file_dialog
        file_menu
      when "x"
        save_file_dialog
        main_menu
      else
      puts "! Not a valid submenu. Try again!"
        file_menu
      end
    end

    def edit_xml_menu
      puts ""
      puts "// #{@current_file_name}"
      puts "//"
      puts "///////////////////////////////// EDIT MENU ////////////////////////////////////////"
      puts "(a) Display complete XML       (4) Move cursor backward  (6) Cursor to parent     //"
      puts "(b) Display current Node       (5) Move cursor forward   (7) Cursor to last child //"
      puts "(1) Insert Node before cursor  (0) Edit Node at cursor   (8) Insert child node    //"
      puts "(2) Insert Node after cursor   (9) Delete Node at cursor (X) Back to file menu    //"
      puts "////////////////////////////////////////////////////////////////////////////////////"
      puts ""

      print "~ Please choose a submenu with number: "
      selected = gets.chomp

      cursor = @xml_document.get_cursor

      case selected.downcase
      # (a) Display complete XML
      when "a"
        puts ""
        puts "~ serialized XML:"
        display_complete_xml
        edit_xml_menu
      # (b) Display current Node
      when "b"
        puts "~ node at cursor:"
        puts ""
        puts cursor.to_xml(2,cursor,false)
        puts ""
        edit_xml_menu
      # (0) Edit Node at cursor
      when "0"
        edit_node_dialog
        edit_xml_menu
      # (1) Insert Node before cursor
      when "1"
        if cursor.is_root?
          puts "! Cannot insert another node at the root level!"
        else
          new_node = add_new_node_dialog

          cursor.insert_before(new_node)
          @xml_document.set_cursor(new_node)
          cursor = @xml_document.get_cursor

          puts ""
          puts "~ Node inserted before cursor with default attributes."
          puts "! Use editing options to change default attributes."
          puts "~ The cursor is moved to the new node:"
          puts ""
          puts cursor.to_xml(2,cursor,false)
          puts ""
        end
        edit_xml_menu
      # (2) Insert Node after cursor
      when "2"
        if cursor.is_root?
          puts "! Cannot insert another node at the root level!"
        else
          new_node = add_new_node_dialog

          cursor.insert_after(new_node)
          @xml_document.set_cursor(new_node)
          cursor = @xml_document.get_cursor

          puts ""
          puts "~ Node inserted after cursor with default attributes."
          puts "! Use editing options to change default attributes."
          puts "~ The cursor is moved to the new node:"
          puts ""
          puts cursor.to_xml(2,cursor,false)
          puts ""
        end
        edit_xml_menu
      # (8) Insert child node
      when "8"
        if cursor.is_a?(XMLModel::LeafNode)
          puts "! Cannot insert new child node to this type of node!"
        else
          new_node = add_new_node_dialog
          cursor.insert_child(new_node)
          @xml_document.set_cursor(new_node)
          cursor = @xml_document.get_cursor

          puts ""
          puts "~ Node inserted with default attributes."
          puts "! Use editing options to change default attributes."
          puts "~ The cursor is moved to the new node:"
          puts ""
          puts cursor.to_xml(2,cursor,false)
          puts ""
        end
        edit_xml_menu
      # (9) Delete Node at cursor
      when "9"
        delete_node_dialog
        edit_xml_menu
      # (4) Move cursor backward
      when "4"
        @xml_document.move_cursor_backward()
        display_complete_xml
        edit_xml_menu
      # (5) Move cursor forward
      when "5"
        @xml_document.move_cursor_forward()
        display_complete_xml
        edit_xml_menu
      # (6) Cursor to parent
      when "6"
        @xml_document.move_cursor_to_parent()
        display_complete_xml
        edit_xml_menu
      # (7) Cursor to last child
      when "7"
        @xml_document.move_cursor_to_last_child()
        display_complete_xml
        edit_xml_menu
      # (X) Back to file menu
      when "x"
          file_menu
      else
          puts "! Not a valid submenu. Try again!"
          edit_xml_menu
      end
    end

  private
    def edit_declaration_dialog
      decl = @xml_document.get_declaration

      puts "~ Current declaration:"
      puts decl.to_xml

      print "~ Do you want to change declaration encoding? (y/n): "
      answ = gets.chomp

      if answ == "y"
        print "~ Please enter new encoding: "
        enc = gets.chomp
        decl.set_encoding(enc)
      end

      print "~ Do you want to change declaration version? (y/n): "
      answ = gets.chomp

      if answ == "y"
        print "~ Please enter new version: "
        vers = gets.chomp
        decl.set_version(vers)
      end

      puts ""
      puts "~ Updated declaration:"
      puts decl.to_xml

      file_menu
    end

    def new_file_dialog
      print "~ Please enter the path for the new file: "
      file_name = gets.chomp

      file_exist = File.file?(file_name)

      if file_exist
        puts "! ERROR: file already exists. Choose another file name!"
        main_menu
      else
        begin
          file = File.open(file_name, "w")
        rescue
          puts "! ERROR: Can't create file."
          main_menu
        else
          @current_file_name = file_name
          @xml_document = XMLModel::Document.new
          puts "~ #{@current_file_name} successfully created."
          file.close
          file_menu
        end
      end
    end

    def open_file_dialog
      print "~ Please enter the path for the file: "
      file_name = gets.chomp

      if File.file?(file_name)
        @current_file_name = file_name

        file = File.open(@current_file_name, "r")
        text = File.read(file)

        @builder = XMLHelper::XMLBuilder.new(text)
        file.close()

        begin
          @xml_document = @builder.build_xml_document()
        rescue XMLHelper::XMLBuildError => error
          print "! ERROR while building XML from file: "
          puts error
          puts "~ Opening file #{@current_file_name} cancelled."
          main_menu
        else
          puts "~ [#{@current_file_name}] successfully opened."
          file_menu
        end
      else
        puts "! The file name you entered is not valid."
        main_menu
      end
    end

    def save_file_dialog
      print "! Do you want to save the current file? (y/n): "
      answ = gets.chomp

      if answ == "y"
        file = File.open(@current_file_name, "w")
        file.write(@xml_document.to_pretty_xml())
        file.close()
      end
    end

    def exit_application_dialog
      print "~ Do you really want to exit? (y/n): "

      selected = gets.chomp

      if selected == "y"
        puts "! XML editor closed."
      else
        puts "! Cancel."
        main_menu
      end
    end

    def edit_node_dialog
      cursor = @xml_document.get_cursor
      cursor.edit
    end

    def delete_node_dialog
      cursor = @xml_document.get_cursor
      if cursor.is_root?
        puts "! The root node cannot be deleted!"
      else
        print "! Do you really want to delete the current node and all subnodes? (y/n): "

        answ = gets.chomp
        if answ == "y"
          node_to_delete = @xml_document.get_cursor
          @xml_document.move_cursor_to_parent
          node_to_delete.delete
        else
          puts "~ Deleting node cancelled."
        end
      end
    end

    def add_new_node_dialog
      puts ""
      puts "  (1) Element"
      puts "  (2) Comment"
      puts "  (3) Plain text"

      print "~ Please select the new node type:"

      answ = gets.chomp

      new_node = XMLModel::Element.new

      case answ.downcase
      when "1"
        new_node = XMLModel::Element.new
      when "2"
        new_node = XMLModel::Comment.new
      when "3"
        new_node = XMLModel::PlainText.new
      else
      puts "! Not a valid selection. Try again!"
        add_new_node_dialog
      end

      return new_node
    end

    def display_complete_xml
      puts ""
      puts @xml_document.to_xml_with_cursor()
      puts ""
    end
  end
end

XMLEditor::Menu.new